#ifndef __M_MATCHER_H__
#define __M_MATCHER_H__

#include <list>
#include <mutex>
#include <condition_variable>
#include "util.hpp"
#include "online.hpp"
#include "db.hpp"
#include "room.hpp"

// 匹配队列
template <class T>
class match_queue
{
public:
    match_queue()
    {}
    int size()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.size();
    }
    bool empty()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.empty();
    }
    void wait() // 阻塞线程
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }
    void push(const T& data) // 入队+唤醒
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.push_back(data);
        _cond.notify_all();
    }
    bool pop(T& data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_list.empty() == true) 
        {
            return false;
        }
        data = _list.front();
        _list.pop_front();
        return true;
    }
    void remove(T& data) // 移除指定数据
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.remove(data);
    }
    ~match_queue()
    {}
private:
    std::list<T> _list; // 队列
    std::mutex _mutex;
    std::condition_variable _cond;
};

// 匹配管理
class matcher_manager
{
private:
    void handle_match(match_queue<uint64_t>& mq)
    {
        while (1)
        {
            while (mq.size() < 2) { mq.wait(); }
            uint64_t uid1, uid2;
            bool ret = mq.pop(uid1);

            if (ret == false) { 
                continue; }
            ret = mq.pop(uid2);
            if (ret == false) {
                add(uid1); continue; } // 将前面移除的用户拿回来
            std::cout << "111" << std::endl;
            wsserver_t::connection_ptr conn1 = _om->get_conn_from_hall(uid1); // 获取用户1信息
            if (conn1.get() == nullptr) { add(uid2); continue; }
            wsserver_t::connection_ptr conn2 = _om->get_conn_from_hall(uid2); // 获取用户2信息
            if (conn2.get() == nullptr) { add(uid1); continue; }

            // 为两个玩家创建房间
            room_ptr rp = _rm->create_room(uid1, uid2);
            if (rp.get() == nullptr) { add(uid1); add(uid2); continue; }
            // 对两个玩家进行响应
            Json::Value resp;
            resp["optype"] = "match_success";
            resp["result"] = true;
            std::string body;
            json_util::serialize(resp, body);
            conn1->send(body);
            conn2->send(body);
        }
    }
    void th_bronze_entry() { handle_match(_q_bronze); }
    void th_silver_entry() { handle_match(_q_silver); }
    void th_gold_entry() { handle_match(_q_gold); }
public:
    matcher_manager(room_manager* rm, user_table* ut, online_manager* om)
    :_rm(rm), _ut(ut), _om(om)
    ,_th_bronze(std::thread(&matcher_manager::th_bronze_entry, this))
    ,_th_silver(std::thread(&matcher_manager::th_silver_entry, this))
    ,_th_gold(std::thread(&matcher_manager::th_gold_entry, this))
    {
        DLOG("游戏匹配模块初始化完毕！");
    }
    bool add(uint64_t uid)
    {
        // 根据天梯分数加入到不同的队列
        Json::Value user;
        bool ret = _ut->select_by_id(uid, user);
        if (ret == false)
        {
            DLOG("获取玩家：%ld 信息失败！", uid);
            return false;
        }
        int score = user["score"].asInt();
        if (score < 2000)
        {
            _q_bronze.push(uid);
        }
        else if (score >= 2000 && score < 3000)
        {
            _q_silver.push(uid);
        }
        else
        {
            _q_gold.push(uid);
        }
        return true;
    }
    bool del(uint64_t uid)
    {
        Json::Value user;
        bool ret = _ut->select_by_id(uid, user);
        if (ret == false)
        {
            DLOG("获取玩家：%ld 信息失败！", uid);
            return false;
        }
        int score = user["score"].asInt();
        if (score < 2000)
        {
            _q_bronze.remove(uid);
        }
        else if (score >= 2000 && score < 3000)
        {
            _q_silver.remove(uid);
        }
        else
        {
            _q_gold.remove(uid);
        }
        return true;
    }
    ~matcher_manager()
    {}
private:
    match_queue<uint64_t> _q_bronze; // 青铜匹配队列
    match_queue<uint64_t> _q_silver; // 白银匹配队列
    match_queue<uint64_t> _q_gold;   // 黄金匹配队列
    // 对应三个队列的线程
    std::thread _th_bronze;
    std::thread _th_silver;
    std::thread _th_gold;

    room_manager* _rm;
    user_table* _ut;
    online_manager* _om;
};

#endif